import {
  Controller,
  Post,
  UseGuards,
  Body,
  HttpException,
  HttpStatus,
  BadRequestException,
  Req,
} from '@nestjs/common';
import {
  ApiTags,
  ApiOperation,
  ApiBearerAuth,
  ApiConsumes,
} from '@nestjs/swagger';
import { CurrentUser } from 'src/decorators/current.user';
import { CurrentRole } from '@/decorators/current.role';
import { ClientRole } from '@/modules/user/role/role.type';
import { UserEntity } from 'src/types/modules/user/entities/user.entity';
import { JwtAuthGuard } from '../../../../../modules/user/jwt/jwt-auth.guard';
import {
  ApiProjectExportReqDto,
  ApiProjectImportReqDto,
  ApiProjectExportResDto,
  ApiProjectImportResDto,
  ApiMinioUploadReqDto,
  ApiMinioUploadResDto,
  ApiProjectResourcesUploadReqDto,
  ApiProjectResourcesUploadResDto,
  ApiProjectMinioInfoReqDto,
  ApiProjectMinioInfoResDto,
} from './dto/project-export.dto';
import { ProjectExportService } from './project-export.service';
import * as fs from 'fs';
import * as path from 'path';
import * as crypto from 'crypto';
import { FastifyRequest } from 'fastify';

// 定义 Fastify 文件对象类型
interface FastifyFileData {
  filename: string;
  mimetype: string;
  encoding: string;
  fieldname: string;
  bytes: number;
  toBuffer(): Promise<Buffer>;
  fields?: any;
}

// 扩展 FastifyRequest 类型
interface FastifyRequestWithFile extends FastifyRequest {
  file(): Promise<FastifyFileData | null>;
}

@ApiTags('Project Export/Import')
@ApiBearerAuth()
@Controller('editor/project-export')
export class ProjectExportController {
  constructor(private readonly projectExportService: ProjectExportService) {}

  @ApiOperation({ summary: '导出项目' })
  @UseGuards(JwtAuthGuard)
  @Post('export')
  async exportProject(
    @Body() body: ApiProjectExportReqDto,
    @CurrentUser() user: UserEntity,
    @CurrentRole() role: ClientRole,
  ): Promise<ApiProjectExportResDto> {
    try {
      const {
        projectId,
        fileName,
        uploadToMinio,
        minioFileName,
        keepLocalCopy,
      } = body;

      if (!projectId) {
        throw new BadRequestException('项目ID不能为空');
      }

      // 检查项目权限
      const hasPermission = await this.checkProjectPermission(
        projectId,
        user.id,
        role.teamId,
      );
      if (!hasPermission) {
        throw new BadRequestException('您无权导出该项目');
      }

      const result = await this.projectExportService.exportProject(
        projectId,
        fileName,
        {
          uploadToMinio,
          minioFileName,
          keepLocalCopy,
        },
      );
      return result;
    } catch (error) {
      console.error('导出项目失败:', error);
      throw new HttpException(
        error.message || '导出项目失败',
        HttpStatus.BAD_REQUEST,
      );
    }
  }

  @ApiOperation({ summary: '导入项目' })
  @UseGuards(JwtAuthGuard)
  @Post('import')
  @ApiConsumes('multipart/form-data')
  async importProject(
    @Req() req: FastifyRequestWithFile,
    @CurrentUser() user: UserEntity,
    @CurrentRole() role: ClientRole,
  ): Promise<ApiProjectImportResDto> {
    try {
      // 使用 Fastify 原生 API 获取文件
      const data = await req.file();

      if (!data) {
        throw new BadRequestException('请选择要导入的ZIP文件');
      }

      console.log('Fastify file data:', {
        mimetype: data.mimetype,
        filename: data.filename,
        fieldname: data.fieldname,
        encoding: data.encoding,
        bytes: data.bytes,
      });

      // 检查文件类型
      const fileType = data.mimetype || '';
      const fileName = data.filename || '';

      console.log('file type:', fileType, 'file name:', fileName);

      if (!fileType.includes('zip') && !fileName.endsWith('.zip')) {
        throw new BadRequestException('只支持ZIP文件格式');
      }

      // 获取文件 buffer 并验证大小
      const buffer = await data.toBuffer();
      const fileSize = data.bytes || buffer.length;

      console.log('file size (from data.bytes):', data.bytes);
      console.log('file size (from buffer):', buffer.length);
      console.log('final file size:', fileSize);

      if (fileSize > 50 * 1024 * 1024) {
        throw new BadRequestException('文件大小不能超过50MB');
      }

      // 获取其他表单数据
      const body = data.fields || {};
      const overwrite = body.overwrite?.value === 'true';
      const namePrefix = body.namePrefix?.value;

      // 验证文件安全性
      const isValidFile = await this.validateZipFileFromBuffer(data);
      if (!isValidFile) {
        throw new BadRequestException('ZIP文件格式无效或存在安全风险');
      }

      // 创建临时文件 - 使用 public/temp 文件夹
      const projectRoot = path.resolve(__dirname, '../../../../../');
      const tempDir = path.join(projectRoot, 'public', 'temp');

      console.log(`项目根目录: ${projectRoot}`);
      console.log(`临时目录: ${tempDir}`);

      if (!fs.existsSync(tempDir)) {
        fs.mkdirSync(tempDir, { recursive: true });
        console.log(`创建临时目录: ${tempDir}`);
      }

      const tempFileName = `import_${Date.now()}_${crypto
        .randomBytes(8)
        .toString('hex')}.zip`;
      const tempFilePath = path.join(tempDir, tempFileName);

      // 保存文件到临时目录
      fs.writeFileSync(tempFilePath, buffer);

      console.log(
        `临时文件已保存: ${tempFilePath}, 大小: ${buffer.length} bytes`,
      );

      try {
        const result = await this.projectExportService.importProject(
          tempFilePath,
          {
            overwrite,
            namePrefix,
          },
        );

        // 如果导入成功，更新项目所有者信息
        if (result.success && result.projectId) {
          await this.updateProjectOwnership(
            result.projectId,
            user.id,
            role.teamId,
          );
        }

        return result;
      } finally {
        // 清理临时文件
        if (fs.existsSync(tempFilePath)) {
          fs.unlinkSync(tempFilePath);
        }
      }
    } catch (error) {
      console.error('导入项目失败:', error);
      throw new HttpException(
        error.message || '导入项目失败',
        HttpStatus.BAD_REQUEST,
      );
    }
  }

  @ApiOperation({ summary: '清理过期文件' })
  @UseGuards(JwtAuthGuard)
  @Post('cleanup')
  async cleanupExpiredFiles(): Promise<{ success: boolean; message: string }> {
    try {
      await this.projectExportService.cleanupExpiredFiles();
      return {
        success: true,
        message: '过期文件清理完成',
      };
    } catch (error) {
      console.error('清理过期文件失败:', error);
      throw new HttpException(
        error.message || '清理过期文件失败',
        HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }
  }

  /**
   * 检查项目权限
   */
  private async checkProjectPermission(
    projectId: string,
    userId: number,
    teamId: number,
  ): Promise<boolean> {
    try {
      const project = await this.projectExportService['projectModel'].findById(
        projectId,
      );
      if (!project) {
        return false;
      }

      // 项目所有者或团队成员可以导出
      if (project.userId === userId || project.teamId === teamId) {
        return true;
      }

      // 检查是否在项目成员列表中
      if (project.member && Array.isArray(project.member)) {
        return project.member.some((member) => member.userId === userId);
      }

      return false;
    } catch (error) {
      console.error('检查项目权限失败:', error);
      return false;
    }
  }

  /**
   * 更新项目所有权信息
   */
  private async updateProjectOwnership(
    projectId: string,
    userId: number,
    teamId: number,
  ): Promise<void> {
    try {
      await this.projectExportService['projectModel'].updateOne(
        { _id: projectId },
        {
          userId,
          teamId,
          update_time: Date.now(),
        },
      );

      // 同时更新相关文档和类型的所有权
      await this.projectExportService['documentModel'].updateMany(
        { projectId },
        {
          userId,
          teamId,
          update_time: Date.now(),
        },
      );

      await this.projectExportService['typeModel'].updateMany(
        { projectId },
        {
          userId,
          teamId,
          update_time: Date.now(),
        },
      );
    } catch (error) {
      console.error('更新项目所有权失败:', error);
    }
  }

  @ApiOperation({ summary: '仅上传到Minio' })
  @UseGuards(JwtAuthGuard)
  @Post('upload-to-minio')
  async uploadToMinioOnly(
    @Body() body: ApiMinioUploadReqDto,
    @CurrentUser() user: UserEntity,
    @CurrentRole() role: ClientRole,
  ): Promise<ApiMinioUploadResDto> {
    try {
      const { projectId, fileName } = body;

      if (!projectId) {
        throw new BadRequestException('项目ID不能为空');
      }

      // 检查项目权限
      const hasPermission = await this.checkProjectPermission(
        projectId,
        user.id,
        role.teamId,
      );
      if (!hasPermission) {
        throw new BadRequestException('您无权导出该项目');
      }

      const result = await this.projectExportService.uploadToMinioOnly(
        projectId,
        fileName,
      );
      return result;
    } catch (error) {
      console.error('上传到Minio失败:', error);
      throw new HttpException(
        error.message || '上传到Minio失败',
        HttpStatus.BAD_REQUEST,
      );
    }
  }

  @ApiOperation({ summary: '批量上传项目资源到Minio' })
  @UseGuards(JwtAuthGuard)
  @Post('upload-resources-to-minio')
  async uploadProjectResourcesToMinio(
    @Body() body: ApiProjectResourcesUploadReqDto,
    @CurrentUser() user: UserEntity,
    @CurrentRole() role: ClientRole,
  ): Promise<ApiProjectResourcesUploadResDto> {
    try {
      const { projectId, resources } = body;

      if (!projectId) {
        throw new BadRequestException('项目ID不能为空');
      }

      if (!resources || !Array.isArray(resources) || resources.length === 0) {
        throw new BadRequestException('资源列表不能为空');
      }

      // 检查项目权限
      const hasPermission = await this.checkProjectPermission(
        projectId,
        user.id,
        role.teamId,
      );
      if (!hasPermission) {
        throw new BadRequestException('您无权操作该项目');
      }

      // 将base64字符串转换为Buffer
      const resourceBuffers = resources.map((resource) => ({
        ...resource,
        buffer: Buffer.from(resource.buffer, 'base64'),
      }));

      const result =
        await this.projectExportService.uploadProjectResourcesToMinio(
          projectId,
          resourceBuffers,
        );
      return result;
    } catch (error) {
      console.error('批量上传资源失败:', error);
      throw new HttpException(
        error.message || '批量上传资源失败',
        HttpStatus.BAD_REQUEST,
      );
    }
  }

  @ApiOperation({ summary: '获取项目Minio存储信息' })
  @UseGuards(JwtAuthGuard)
  @Post('minio-info')
  async getProjectMinioInfo(
    @Body() body: ApiProjectMinioInfoReqDto,
    @CurrentUser() user: UserEntity,
    @CurrentRole() role: ClientRole,
  ): Promise<ApiProjectMinioInfoResDto> {
    try {
      const { projectId } = body;

      if (!projectId) {
        throw new BadRequestException('项目ID不能为空');
      }

      // 检查项目权限
      const hasPermission = await this.checkProjectPermission(
        projectId,
        user.id,
        role.teamId,
      );
      if (!hasPermission) {
        throw new BadRequestException('您无权查看该项目');
      }

      const result = await this.projectExportService.getProjectMinioInfo(
        projectId,
      );
      return result;
    } catch (error) {
      console.error('获取Minio信息失败:', error);
      throw new HttpException(
        error.message || '获取Minio信息失败',
        HttpStatus.BAD_REQUEST,
      );
    }
  }

  @ApiOperation({ summary: '删除项目Minio文件' })
  @UseGuards(JwtAuthGuard)
  @Post('delete-from-minio')
  async deleteProjectFromMinio(
    @Body() body: ApiProjectMinioInfoReqDto,
    @CurrentUser() user: UserEntity,
    @CurrentRole() role: ClientRole,
  ): Promise<{ success: boolean; message?: string; error?: string }> {
    try {
      const { projectId } = body;

      if (!projectId) {
        throw new BadRequestException('项目ID不能为空');
      }

      // 检查项目权限（只有项目所有者可以删除）
      const hasPermission = await this.checkProjectPermission(
        projectId,
        user.id,
        role.teamId,
      );
      if (!hasPermission) {
        throw new BadRequestException('您无权删除该项目文件');
      }

      const result = await this.projectExportService.deleteProjectFromMinio(
        projectId,
      );
      return {
        success: result.success,
        message: result.success ? 'Minio文件删除成功' : result.error,
        error: result.error,
      };
    } catch (error) {
      console.error('删除Minio文件失败:', error);
      throw new HttpException(
        error.message || '删除Minio文件失败',
        HttpStatus.BAD_REQUEST,
      );
    }
  }

  /**
   * 验证ZIP文件安全性 - 从 Fastify 文件对象
   */
  private async validateZipFileFromBuffer(
    data: FastifyFileData,
  ): Promise<boolean> {
    try {
      // 检查文件大小
      if (data.bytes > 50 * 1024 * 1024) {
        return false;
      }

      // 获取文件 buffer
      const buffer = await data.toBuffer();

      // 检查文件头是否为有效的ZIP格式
      if (buffer.length < 4) {
        return false;
      }

      // ZIP文件头标识: 0x50 0x4B 0x03 0x04 或 0x50 0x4B 0x05 0x06
      const header = buffer.slice(0, 4);
      const isValidZipHeader =
        (header[0] === 0x50 &&
          header[1] === 0x4b &&
          header[2] === 0x03 &&
          header[3] === 0x04) ||
        (header[0] === 0x50 &&
          header[1] === 0x4b &&
          header[2] === 0x05 &&
          header[3] === 0x06) ||
        (header[0] === 0x50 &&
          header[1] === 0x4b &&
          header[2] === 0x07 &&
          header[3] === 0x08);

      if (!isValidZipHeader) {
        console.log('Invalid ZIP header:', header);
        return false;
      }

      console.log('ZIP file validation passed, size:', buffer.length);
      return true;
    } catch (error) {
      console.error('验证ZIP文件失败:', error);
      return false;
    }
  }

  /**
   * 验证ZIP文件安全性 - 兼容旧版本
   */
  private async validateZipFile(file: any): Promise<boolean> {
    try {
      // 如果是 Fastify 文件对象
      if (file.toBuffer && typeof file.toBuffer === 'function') {
        return await this.validateZipFileFromBuffer(file);
      }

      // 旧的处理逻辑
      let fileSize = 0;
      if (file.file && file.file.bytesRead) {
        fileSize = file.file.bytesRead;
      } else if (file.buffer) {
        fileSize = file.buffer.length;
      } else if (file.size) {
        fileSize = file.size;
      }

      if (fileSize > 50 * 1024 * 1024) {
        return false;
      }

      // 获取文件 buffer
      let buffer: Buffer;
      if (file.file) {
        buffer = await file.toBuffer();
      } else if (file.buffer) {
        buffer = file.buffer;
      } else {
        return false;
      }

      // 检查文件头是否为有效的ZIP格式
      if (buffer.length < 4) {
        return false;
      }

      // ZIP文件头标识
      const header = buffer.slice(0, 4);
      const isValidZipHeader =
        (header[0] === 0x50 &&
          header[1] === 0x4b &&
          header[2] === 0x03 &&
          header[3] === 0x04) ||
        (header[0] === 0x50 &&
          header[1] === 0x4b &&
          header[2] === 0x05 &&
          header[3] === 0x06) ||
        (header[0] === 0x50 &&
          header[1] === 0x4b &&
          header[2] === 0x07 &&
          header[3] === 0x08);

      if (!isValidZipHeader) {
        return false;
      }

      return true;
    } catch (error) {
      console.error('验证ZIP文件失败:', error);
      return false;
    }
  }
}
